#include "ota_version.h"
#include "ota_http_curl.h"
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <unistd.h>
#include <sys/reboot.h>
#include  "log.h"

/**
 * @brief  根据文件路径，把对应的文件生产一个sha1码
 * @param  file_path 文件路径
 * @return 返回sha1码字符串
 *
 */
char *ota_version_sha1(char *file_path)
{
    FILE *file = fopen(file_path, "rb");
    if (!file)
    {
        perror("Could not open file");
        return NULL;
    }

    unsigned char sha1_hash[SHA_DIGEST_LENGTH];
    SHA_CTX sha1_ctx;
    SHA1_Init(&sha1_ctx);

    unsigned char buffer[4096];
    size_t bytes_read;

    while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) != 0)
    {
        SHA1_Update(&sha1_ctx, buffer, bytes_read);
    }

    SHA1_Final(sha1_hash, &sha1_ctx);
    fclose(file);

    // Allocate memory for the SHA1 hash string (40 hex digits + 1 null terminator)
    char *sha1_string = (char *)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!sha1_string)
    {
        perror("Memory allocation failed");
        return NULL;
    }

    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i)
    {
        sprintf(&sha1_string[i * 2], "%02x", sha1_hash[i]);
    }

    return sha1_string;
}

/**
 * @brief 用于检查和更新程序版本
 * @return 0 表示成功， -1表示失败
 * 1 访问ota服务器的程序信息
    2 把json信息 提取出来
    3用本地的版本号和服务的版本号进行比较
   4 如果本地版本号低 除非更新
   5 下载程序包
   6 用程序包文件本地生成 验证码
  7 用本地验证码和服务器上的验证码进行比较
 8 如果一致则下载完成
  9重启网关

 *
 */
int ota_version_check_update()
{

    //     * 1 访问ota服务器的程序信息
    response_body_t *response_body = ota_http_curl_get(APP_VERSION_INFO_URL);

    //     2 把json信息 提取出来
    cJSON *root = cJSON_Parse(response_body->str);
    cJSON *sha_cjson = cJSON_GetObjectItem(root, "sha1");
    cJSON *major_cjson = cJSON_GetObjectItem(root, "major");
    cJSON *minor_cjson = cJSON_GetObjectItem(root, "minor");
    cJSON *patch_cjson = cJSON_GetObjectItem(root, "patch");

    char *sha_remote = sha_cjson->valuestring;
    int major_remote = major_cjson->valueint;
    int minor_remote = minor_cjson->valueint;
    int patch_remote = patch_cjson->valueint;

    //     3用本地的版本号和服务的版本号进行比较
    if (APP_VERSION_MAJOR < major_remote 
        || (APP_VERSION_MAJOR == major_remote && APP_VERSION_MINOR < minor_remote) 
        || (APP_VERSION_MAJOR == major_remote && APP_VERSION_MINOR == minor_remote && APP_VERSION_PATCH < patch_remote))
    {
        log_info("检测到有新版本 %d.%d.%d",major_remote,minor_remote,patch_remote);
        //    4 如果本地版本号低 触发更新
        //    5 下载程序包
        int ret = ota_http_curl_download(APP_VERSION_FILE_URL, APP_VERSION_FILE_LOCAL_PATH);
        //    6 用程序包文件本地生成 验证码
        if (ret == 0)
        {
            char *sha1_local = ota_version_sha1(APP_VERSION_FILE_LOCAL_PATH);
            log_info("sha1_local=%s", sha1_local);
            //   7 用本地验证码和服务器上的验证码进行比较
            if (strcmp(sha1_local, sha_remote) == 0)
            {
                printf("下载完成\n");
                //  8 如果一致则下载完成
                //   9重启网关
                reboot(RB_AUTOBOOT);
            }
            else
            {
                printf("下载文件残缺\n");
                unlink(APP_VERSION_FILE_LOCAL_PATH);
                return -1;
            }
        }else
        {
            printf("下载失败\n");
            return -1;
        }
    }

    return 0;
}

/**
 * @brief 每日检查一次版本更新
 */
int ota_version_check_update_daily()
{
    while (1)
    {
        sleep(24 * 60 * 60);
        ota_version_check_update();
    }
}

/**
 * @brief 获取当前版本号
 * 
 */
void ota_version_print()
{
    printf("当前版本号：%d.%d.%d\n", APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_VERSION_PATCH);
}